Skip to content

[pull] master from ruby:master - #1348

Merged
pull[bot] merged 16 commits into
turkdevops:masterfrom
ruby:master
Aug 25, 2026
Merged

[pull] master from ruby:master#1348
pull[bot] merged 16 commits into
turkdevops:masterfrom
ruby:master

Conversation

@pull

@pull pull Bot commented Aug 25, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Earlopain and others added 16 commits August 25, 2026 13:15
ruby/prism@9df2a21 changed the comment style

Now rdoc picks this up. The comment doesn't say much, seems fine to just remove

ruby/prism@f703c615ae
With gcc 15.2.0 on aarch64 Ubuntu 26.4:

```console
hash.c: In function ‘rb_hash_s_create’:
hash.c:1982:20: warning: ‘hash’ may be used uninitialized [-Wmaybe-uninitialized]
 1982 |             return hash;
      |                    ^~~~
hash.c:1920:11: note: ‘hash’ was declared here
 1920 |     VALUE hash, tmp;
      |           ^~~~
```
With gcc 15.2.0 on aarch64 Ubuntu 26.4:

```console
io_buffer.c: In function ‘io_buffer_flags_for_new’:
io_buffer.c:978:20: warning: comparison between ‘enum rb_io_buffer_flags’ and ‘enum <anonymous>’ [-Wenum-compare]
  978 |     if (allocation == RB_IO_BUFFER_ALLOCATION_FLAGS) {
      |                    ^~
```
With gcc 15.2.0 on aarch64 Ubuntu 26.4:

```console
ractor_sync.c: In function ‘ractor_basket_new.constprop’:
ractor_sync.c:1093:82: warning: argument ‘type’ might be clobbered by ‘longjmp’ or ‘vfork’ [-Wclobbered]
 1093 | ractor_basket_new(rb_execution_context_t *ec, VALUE obj, enum ractor_basket_type type, bool exc)
      |                                                          ~~~~~~~~~~~~~~~~~~~~~~~~^~~~
```
Prevent a tail call from discarding saved machine-register roots
before `rb_gc_mark_roots` scans the machine stack.
For now it still returns a constant, but clarify when we're looking
for the max bound, versus a miss, etc.
Instead of always allocating `ar_table` backed hashes in 160B
slots for them to have capacity of `RHASH_AR_TABLE_MAX_SIZE` (`8`),
they can now be allocated in any slot size between `64B` and `160B`.

`64B` is the minimum slot size that still allows transitioning to
an `st_table` if necessary.

The assumption is that there is a large number of literal hashes
and keyword argument hashes being built, and the overwhelming majority
of them aren't appended to.

When this assumption hold, this patch saves memory and reduce GC
pressure by allocating in a smaller slot than before.

However when the assumption doesn't hold, it has the oppositve effect
as the Hash will transition to an `st_table` when before it may have
stayed an `ar_table`.

Currently the main blocked for this change is that the compiler
has a tendency to generate code that make the final Hash size unknown.

For instance: `{a: 4, b: 4 + 1}` is compiled as:

```
0000 duphash                                {a: 4}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 putobject                              :b
0007 putobject                              4
0009 putobject_INT2FIX_1_
0010 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]
0012 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:3, ARGS_SIMPLE>
```

Here `duphash` has no information about how large of a hash it needs to allocate.
For this patch to be more efficient the compiler should generate something like:

```
0000 putobject                              {a: 4}                    (   1)[Li]
0002 putspecialobject                       1
0004 swap
0005 putobject                              :b
0007 putobject                              4
0009 putobject_INT2FIX_1_
0010 opt_plus                               <calldata!mid:+, argc:1, ARGS_SIMPLE>[CcCr]
0012 opt_send_without_block                 <calldata!mid:core#hash_merge_ptr, argc:3, ARGS_SIMPLE>
```

So that it's `hash_merge_ptr` that is responsible for allocating the final hash,
given it does have a much better clue of how large it would need to be.

Demo:

```ruby
require 'objspace'
def size(hash)
  puts "size: #{hash.size}\tmemsize: #{ObjectSpace.memsize_of(hash)}"
end

size({})
size(a:1)
size(a:1, b:2)
size(a:1, b:2, c:3)
size(a:1, b:2, c:3, d:4)
size(a:1, b:2, c:3, d:4, e:5)
size(a:1, b:2, c:3, d:4, e:5, f:6)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8)
size(a:1, b:2, c:3, d:4, e:5, f:6, g:7, h:8, i:9)
```

Before:

```
size: 0	memsize: 160
size: 1	memsize: 160
size: 2	memsize: 160
size: 3	memsize: 160
size: 4	memsize: 160
size: 5	memsize: 160
size: 6	memsize: 160
size: 7	memsize: 160
size: 8	memsize: 160
size: 9	memsize: 464
```

After:

```
size: 0	memsize: 64
size: 1	memsize: 64
size: 2	memsize: 64
size: 3	memsize: 80
size: 4	memsize: 96
size: 5	memsize: 128
size: 6	memsize: 128
size: 7	memsize: 160
size: 8	memsize: 160
size: 9	memsize: 448
```
This is designed to replace rb_ident_hash_new calls when such hashes
are used purely with with true values.

To implement this, add a set_alloc_with_size_and_type static function,
and have set_alloc_with_size and rb_ident_set_new call it.
This used a hash with all true values, with is simple to convert
to a set to save on memory when flattening array with a large
number of nested elements.
Keep the payload builder uninlined in optimized GCC builds because
inlining causes false-positive `-Wclobbered` warnings.
`hash_copy` will call `st_init_existing_table_with_size` which
allocates and may trigger GC causing the current hash to be marked.

So we need to zero-out the `st_table` to avoid a segfault.
@pull pull Bot locked and limited conversation to collaborators Aug 25, 2026
@pull pull Bot added the ⤵️ pull label Aug 25, 2026
@pull
pull Bot merged commit abc5a92 into turkdevops:master Aug 25, 2026
1 of 3 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants